package com.example.utils;

import com.google.common.hash.HashFunction;
import com.google.common.hash.Hashing;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.poi.hslf.usermodel.HSLFShape;
import org.apache.poi.hslf.usermodel.HSLFSlide;
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFShape;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;



public class LSHUtil {

    private static final int NUM_HASH_FUNCTIONS = 100;
    private static final List<HashFunction> hashFunctions = new ArrayList<>();

    static {
        for (int i = 0; i < NUM_HASH_FUNCTIONS; i++) {
            hashFunctions.add(Hashing.murmur3_128(i));
        }
    }

    // 基于数值特征向量计算MinHash
    public static long[] minHash(double[] features) {
        long[] minHashes = new long[NUM_HASH_FUNCTIONS];
        Arrays.fill(minHashes, Long.MAX_VALUE);

        for (double feature : features) {
            for (int i = 0; i < NUM_HASH_FUNCTIONS; i++) {
                long hash = hashFunctions.get(i).hashLong(Double.doubleToLongBits(feature)).asLong();
                minHashes[i] = Math.min(minHashes[i], hash);
            }
        }
        return minHashes;
    }

    // 基于字符串内容计算MinHash（保持原有功能）
    public static long[] minHash(Set<String> set) {
        long[] minHashes = new long[NUM_HASH_FUNCTIONS];
        Arrays.fill(minHashes, Long.MAX_VALUE);

        for (String element : set) {
            for (int i = 0; i < NUM_HASH_FUNCTIONS; i++) {
                long hash = hashFunctions.get(i).hashString(element, StandardCharsets.UTF_8).asLong();
                minHashes[i] = Math.min(minHashes[i], hash);
            }
        }
        return minHashes;
    }

    // 提取文本文档中的Shingles
    public static Set<String> getShingles(String content, int k) {
        Set<String> shingles = new HashSet<>();
        for (int i = 0; i <= content.length() - k; i++) {
            shingles.add(content.substring(i, i + k));
        }
        return shingles;
    }

    // 读取文件内容，根据文件类型选择不同处理方式
    public static String readFile(String path) throws IOException {
        if (path.endsWith(".docx")) {
            return readDocxFile(path);
        } else if (path.endsWith(".pdf")) {
            return readPdfFile(path);
        } else if (path.endsWith(".doc")) {
            return readDocFile(path);
        } else if (path.endsWith(".xlsx") || path.endsWith(".xls")) {
            return readExcelFile(path);
        } else if (path.endsWith(".pptx")) {
            return readPptxFile(path);
        } else if (path.endsWith(".ppt")) {
            return readPptFile(path);
        } else if (isImageFile(path)) {
            return null; // 图像文件不需要以字符串形式读取
        } else if (isAudioFile(path)) {
            return null; // 音频文件不需要以字符串形式读取
        } else {
            return new String(Files.readAllBytes(Paths.get(path)), StandardCharsets.UTF_8);
        }
    }

    public static String readDocxFile(String path) throws IOException {
        try (FileInputStream fis = new FileInputStream(path);
             XWPFDocument doc = new XWPFDocument(fis);
             XWPFWordExtractor extractor = new XWPFWordExtractor(doc)) {
            return extractor.getText();
        }
    }

    public static String readPdfFile(String path) throws IOException {
        try (PDDocument document = PDDocument.load(new File(path))) {
            PDFTextStripper pdfStripper = new PDFTextStripper();
            return pdfStripper.getText(document);
        }
    }

    public static String readDocFile(String path) throws IOException {
        try (FileInputStream fis = new FileInputStream(path);
             HWPFDocument doc = new HWPFDocument(fis);
             WordExtractor extractor = new WordExtractor(doc)) {
            return extractor.getText();
        }
    }

    public static String readExcelFile(String path) throws IOException {
        StringBuilder textContent = new StringBuilder();
        try (FileInputStream fis = new FileInputStream(path);
             Workbook workbook = path.endsWith(".xlsx") ? new XSSFWorkbook(fis) : WorkbookFactory.create(fis)) {

            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                Sheet sheet = workbook.getSheetAt(i);
                for (Row row : sheet) {
                    for (Cell cell : row) {
                        String cellText = getCellText(cell);
                        textContent.append(cellText).append("\t");
                    }
                    textContent.append("\n");
                }
                textContent.append("\n");
            }
        }
        return textContent.toString();
    }
    private static String getCellText(Cell cell) {
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    return Double.toString(cell.getNumericCellValue());
                }
            case BOOLEAN:
                return Boolean.toString(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            case BLANK:
                return "";
            default:
                return "Unknown Cell Type";
        }
    }
    public static String readPptxFile(String path) throws IOException {
        StringBuilder textContent = new StringBuilder();
        try (FileInputStream fis = new FileInputStream(path);
             XMLSlideShow ppt = new XMLSlideShow(fis)) {

            for (XSLFSlide slide : ppt.getSlides()) {
                for (XSLFShape shape : slide.getShapes()) {
                    if (shape instanceof org.apache.poi.xslf.usermodel.XSLFTextShape) {
                        textContent.append(((org.apache.poi.xslf.usermodel.XSLFTextShape) shape).getText()).append("\n");
                    }
                }
            }
        }
        return textContent.toString();
    }

    public static String readPptFile(String path) throws IOException {
        StringBuilder textContent = new StringBuilder();
        try (FileInputStream fis = new FileInputStream(path);
             HSLFSlideShow ppt = new HSLFSlideShow(fis)) {

            for (HSLFSlide slide : ppt.getSlides()) {
                for (HSLFShape shape : slide.getShapes()) {
                    if (shape instanceof org.apache.poi.hslf.usermodel.HSLFTextShape) {
                        textContent.append(((org.apache.poi.hslf.usermodel.HSLFTextShape) shape).getText()).append("\n");
                    }
                }
            }
        }
        return textContent.toString();
    }

    // 提取图像文件的数值特征
    public static double[] extractImageFeatures(String imagePath) throws IOException {
        BufferedImage image = ImageIO.read(new File(imagePath));
        int width = image.getWidth();
        int height = image.getHeight();
        double[] features = new double[width * height];

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int rgb = image.getRGB(x, y);
                int red = (rgb >> 16) & 0xFF;
                int green = (rgb >> 8) & 0xFF;
                int blue = rgb & 0xFF;
                // 使用标准的灰度转换公式
                double gray = 0.299 * red + 0.587 * green + 0.114 * blue;
                features[y * width + x] = gray;
            }
        }
        return features;
    }

    // 假设这是音频文件的特征提取函数，实际应用中可以使用MFCC等方法
    public static double[] extractAudioFeatures(String audioPath) {
        return new double[]{/*音频特征数据*/};
    }

    // 判断文件是否为图片文件
    private static boolean isImageFile(String path) {
        return path.endsWith(".png") || path.endsWith(".jpg") || path.endsWith(".jpeg");
    }

    // 判断文件是否为音频文件
    private static boolean isAudioFile(String path) {
        return path.endsWith(".wav") || path.endsWith(".mp3");
    }

    // 根据文件类型获取哈希Key
    public static long[] getHashKey(String filePath) throws IOException {
        if (isImageFile(filePath)) {
            double[] features = extractImageFeatures(filePath);
            return minHash(features);
        } else if (isAudioFile(filePath)) {
            double[] features = extractAudioFeatures(filePath);
            return minHash(features);
        } else {
//            System.out.println("111111111111111111111111111111111111111111");
            String fileContent = readFile(filePath);
            if (fileContent != null) {
                int shingleSize = 5; // 根据需要调整shingle大小
                Set<String> shingles = getShingles(fileContent, shingleSize);
                return minHash(shingles);
            }
            return null; // 对于不支持的文件类型，返回null
        }
    }

    // 计算两个哈希Key的相似度
    public static double calculateSimilarity(long[] minHash1, long[] minHash2) {
        if (minHash1 == null || minHash2 == null) {
            return 0.0;
        }
        int count = 0;
        for (int i = 0; i < NUM_HASH_FUNCTIONS; i++) {
            if (minHash1[i] == minHash2[i]) {
                count++;
            }
        }
        return (double) count / NUM_HASH_FUNCTIONS;
    }


}
